﻿using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Threading;
using System.Windows.Forms;
using PPClasses;
using PortalPlan.Solvers;

namespace PortalPlan
{
    public partial class Form1 : Form
    {
        private Solver TheSolver;
        private Thread[] T;

        private String SamplePath()
        {
            String sampleFolder = (new FileInfo(Application.ExecutablePath)).DirectoryName + Path.DirectorySeparatorChar + "Samples";
#if DEBUG
            String sf2 = @"..\..\..\..\Samples";
            if (!Directory.Exists(sampleFolder) && Directory.Exists(sf2))
                sampleFolder = sf2;
#endif

            return sampleFolder;
        }


        public Form1()
        {
            InitializeComponent();
            this.Icon = Properties.Resources.ingress;
            integerProgrammingToolStripMenuItem.Checked = true;
            PM.ModeChanged += this.ModeChanged;

            String sampleFolder = SamplePath();

            if (Directory.Exists(sampleFolder))
            {
                foreach (string fn in Directory.GetFiles(sampleFolder))
                {
                    samplesToolStripMenuItem.DropDownItems.Add((new FileInfo(fn)).Name);
                }
            }
            else
            {
                samplesToolStripMenuItem.Enabled = false;
            }

        }

        private void ModeChanged(PictureMarker.Modes mode)
        {
            switch (mode)
            {
                case PictureMarker.Modes.Add:
                    label2.Text = "Click to add portals";
                    break;
                case PictureMarker.Modes.Move:
                    label2.Text = "Click and drag to move portals";
                    break;
                case PictureMarker.Modes.Delete:
                    label2.Text = "Click to delete portals";
                    break;
                default:
                    label2.Text = "";
                    break;
            }
        }

        private void KillAnyThreads()
        {
            if (T != null)
            {
                TheSolver.Stop = true;

                bool anyAlive = false;
                do
                {
                    anyAlive = false;
                    foreach (Thread t in T)
                        if (t.IsAlive)
                            anyAlive = true;
                    if (anyAlive)
                        Thread.Sleep(100);
                } while (anyAlive);

                foreach (Thread t in T)
                {
                    t.Abort();
                }
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            KillAnyThreads();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            label2.Text = TheSolver.StatusText();
            PM.UpdateWith(TheSolver.BestPairs, TheSolver.MustLink);
            if (TheSolver.CompletelyDone || TheSolver.Stop)
            {
                AllDone();
                timer1.Stop();
            }
        }

        private void eToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void startToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Solve();
        }

        private void EnableDisable(bool en)
        {

            object[] DisableDuringSolving = new object[]
                {
                    tsSolve,
                    tsAdd,
                    tsNew,
                    tsMove,
                    tsDelete,
                    tsSave,
                    solverToolStripMenuItem,
                    loadToolStripMenuItem,
                    saveToolStripMenuItem,
                    newToolStripMenuItem,
                    pasteToolStripMenuItem,
                    addToolStripMenuItem,
                    deleteToolStripMenuItem,
                    moveToolStripMenuItem,
                    startToolStripMenuItem,
                    tsPaste,
                    tsOpen,
                    tsSave,
                    PM
                };

            foreach (Object o in DisableDuringSolving)
            {
                if (o is ToolStripItem)
                    (o as ToolStripItem).Enabled = en;
                else if (o is Control)
                    (o as Control).Enabled = en;
                else
                {
#if DEBUG
                    System.Diagnostics.Debug.Fail("Bad control type");
#endif
                }
            }

            tsStop.Enabled = !en;
            stopToolStripMenuItem.Enabled = !en;
        }

        private void AllDone()
        {
            EnableDisable(true);
        }

        private void Solve()
        {
            KillAnyThreads();

            TheSolver = null;
            if (dFSToolStripMenuItem.Checked)
                TheSolver = new DFS(PM.TheData.ThePoints);
            else if (simulatedAnnealingToolStripMenuItem.Checked)
                TheSolver = new SA(PM.TheData.ThePoints);
            else if (flowToolStripMenuItem.Checked)
                TheSolver = new Flow(PM.TheData.ThePoints);
            else if (bruteForceToolStripMenuItem.Checked)
                TheSolver = new BruteForcer(PM.TheData.ThePoints);
            else if (integerProgrammingToolStripMenuItem.Checked)
                TheSolver = new IPRunner(PM.TheData.ThePoints);

            if (TheSolver == null)
                return;

            EnableDisable(false);

            int n = TheSolver.CanThread ? Environment.ProcessorCount : 1;
            T = new Thread[n];
            for (int i = 0; i < n; i++)
            {
                T[i] = new Thread(TheSolver.GoGoGo)
                    {
                        Name = "Solver " + (i + 1), 
                        IsBackground = true
                    };
                T[i].Start();
            }
            timer1.Start();
        }

        private void stopToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Stop();
        }

        private void Stop()
        {
            KillAnyThreads();
            AllDone();
        }

        private void tsSolve_Click(object sender, EventArgs e)
        {
            Solve();
        }

        private void tsStop_Click(object sender, EventArgs e)
        {
            Stop();
        }

        private void addToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PM.Mode = PictureMarker.Modes.Add;
        }

        private void moveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PM.Mode = PictureMarker.Modes.Move;
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PM.Mode = PictureMarker.Modes.Delete;
        }

        private void tsAdd_Click(object sender, EventArgs e)
        {
            PM.Mode = PictureMarker.Modes.Add;
        }

        private void tsMove_Click(object sender, EventArgs e)
        {
            PM.Mode = PictureMarker.Modes.Move;
        }

        private void tsDelete_Click(object sender, EventArgs e)
        {
            PM.Mode = PictureMarker.Modes.Delete;
        }

        private void pasteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DoPaste();
        }

        private void DoPaste()
        {
            if (Clipboard.ContainsImage())
            {
                PM.SetImage(Clipboard.GetImage());
                //PM.GuessPortals();
                //label2.Text = PM.TheData.ThePoints.Count + " portals found";
            }
        }

        private void tsPaste_Click(object sender, EventArgs e)
        {
            DoPaste();
        }

        private void loadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFile();
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFile();
        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            NewFile();
        }

        private void NewFile()
        {
            if (DialogResult.OK !=
                MessageBox.Show("Start new project?", "Portal Plan", MessageBoxButtons.OKCancel, MessageBoxIcon.Question))
                return;

            PM.UpdateWith(null, null);
            PM.TheData.ThePoints.Clear();
            PM.SetImage(null);
            PM.Invalidate();
            label2.Text = "";

        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            (new AboutBox1()).ShowDialog();
        }

        private void tsNew_Click(object sender, EventArgs e)
        {
            NewFile();
        }

        private void solverMenuItemClick(object sender, EventArgs e)
        {
            if (!(sender is ToolStripMenuItem))
                return;

            // make sure only one is checked

            foreach (var x in solverToolStripMenuItem.DropDownItems)
            {
                if (!(x is ToolStripMenuItem))
                    continue;
                (x as ToolStripMenuItem).Checked = false;
            }

            (sender as ToolStripMenuItem).Checked = true;
        }

        private void tsOpen_Click(object sender, EventArgs e)
        {
            OpenFile();
        }

        private void OpenFile()
        {
            if (DialogResult.OK != openFileDialog1.ShowDialog())
                return;

            LoadFile(openFileDialog1.FileName);
        }

        private void LoadFile(String filename)
        {
            Problem dd = Problem.LoadFrom(filename);
            if (dd != null)
            {
                PM.UpdateWith(null, null);
                PM.TheData = dd;
                PM.Invalidate();
                label2.Text = "File loaded";
            }
        }

        private void tsSave_Click(object sender, EventArgs e)
        {
            SaveFile();
        }

        private void SaveFile()
        {
            if (DialogResult.OK != saveFileDialog1.ShowDialog())
                return;

            PM.TheData.SaveTo(saveFileDialog1.FileName);

            label2.Text = "File saved";
        }

        private void removeImageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PM.TheData.TheImage = null;
            PM.Invalidate();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            PM.Mode = PictureMarker.Modes.Add;
        }

        private void samplesToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            LoadFile(SamplePath() + Path.DirectorySeparatorChar + e.ClickedItem.Text);
        }

        private void quickHelpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            (new QuickHelp()).ShowDialog();
        }

    }
}

